#include <math.h>
#include "typedef.h"
#include "work.h"
#include "os_tick.h"
#include "key_driver.h"
#include "key_bsp.h"

//以下时间的设置，应该是KEY_SCAN_TIME的整数倍
#define KEY_SCAN_TIME                   Tnms(5)     //按键扫描周期
#define KEY_DEBOUNCE_TIME               Tnms(30)    //消抖时间
#define KEY_MULTIPLE_INTERVAL           Tnms(200)   //多次按键时间间隔最小，若为0则没有此功能
#define KEY_PRESS_SHORT_TIME            Tnms(700)   //短按时间，若为0则没有此功能
#define KEY_PRESS_LONG_TIME             Tnms(1500)  //长按时间，若为0则没有此功能
#define KEY_PRESS_LONG_HOLD_TIME        Tnms(3000)  //长按hold时间，若为0则没有此功能
#define KEY_PRESS_HOLD_INTERVAL_TIME    Tnms(300)   //长按hold，循环发送时间，若为0则没有此功能

#define KEY_PRESS_DOUBLE_START_YIME     Tnms(200)   //组合键开始时间差,若为0则没有组合键功能
#define KEY_PRESS_DOUBLE_END_YIME       Tnms(500)   //组合键结束时间差

typedef enum
{
    KEY_STEP_IDLE = 0,
    KEY_STEP_DOUBLE_CHECK,
    KEY_STEP_DOUBLE_PROCESS,
    KEY_STEP_DOUBLE_WAIT,
    KEY_STEP_SINGLE_PROCESS,
    KEY_STEP_MULTIPLE_CLICK,
} E_KEY_STEP;

struct key_s
{
    E_KEY index;
    E_KEY_STEP step;
    SysTick_t step_time;
    E_KEY_STATE state;
    E_KEY pair;
    u8 click_cnt;
};

struct key_bsp_s
{
    SysTick_t time;
    key_bsp_callback function;
};
struct key_bsp_s key_bsp={0};


struct key_s keys[KEY_MAX]={\
    {.index = KEY0, .step = KEY_STEP_IDLE}, \
    {.index = KEY1, .step = KEY_STEP_IDLE}, \
    {.index = KEY2, .step = KEY_STEP_IDLE}, \
    {.index = KEY3, .step = KEY_STEP_IDLE}, \
    {.index = KEY4, .step = KEY_STEP_IDLE}, \
    {.index = KEY5, .step = KEY_STEP_IDLE}, \
    {.index = KEY6, .step = KEY_STEP_IDLE}, \

};
static E_KEY key_bsp_keys_get(E_KEY val)
{
    for(int i=0; i<KEY_MAX; i++)//读取所有按键状态
    {
        if(val == keys[i].index)
            return (E_KEY)i;
    }
    return KEY0;
}

static void key_bsp_scan(unsigned int data)
{
    if(0 == systick_get_difference_assign(&key_bsp.time,KEY_SCAN_TIME))
		return ;

    if(NULL==key_bsp.function)
        return;

    for(int i=0; i<KEY_MAX; i++)//读取所有按键状态
    {
        keys[i].state = key_driver_get_pin_state((E_KEY)i);
        keys[i].step_time+=KEY_SCAN_TIME;
    }
    s32 time_double=0;//组合按键先后时间
    u32 double_key=0;
    for(int i=0; i<KEY_MAX; i++)
    {
        E_KEY index=keys[i].index;
        E_KEY pair=keys[i].pair;
        switch(keys[i].step)
        {
            case KEY_STEP_IDLE:
                if(KEY_STATE_ENABLE == keys[i].state) {
                    if(keys[i].step_time>=KEY_DEBOUNCE_TIME) { //消抖
                        keys[i].step = (pair>=KEY_MAX) ? KEY_STEP_SINGLE_PROCESS: KEY_STEP_DOUBLE_CHECK;//有无组合键
                        keys[i].step = KEY_STEP_DOUBLE_CHECK;
                        keys[i].step_time = 0;
                        keys[i].click_cnt = 0;

                        //key_bsp.function(1<<keys[i].index, KEY_PRESS_DOWN);//根据项目情况，进行处理
                    }
                }
                else
                    keys[i].step_time=0;
            break;
            case KEY_STEP_DOUBLE_CHECK://组合键检测，按下有先后，松开也有先后
                pair=key_bsp_keys_get(keys[i].pair);
                if(keys[i].step_time < keys[pair].step_time)
                    time_double = keys[pair].step_time - keys[i].step_time;
                else
                    time_double = keys[i].step_time - keys[pair].step_time;

                if((KEY_STATE_DISABLE == keys[i].state) || (time_double >= KEY_PRESS_DOUBLE_START_YIME))
                {
                    keys[i].step=KEY_STEP_SINGLE_PROCESS;//若组合键一个已经按下执行处理中，则也执行这里，即单按键优先
                }
                else if((KEY_STATE_ENABLE == keys[pair].state))//确认组合键,
                {
                    keys[i].step=KEY_STEP_DOUBLE_PROCESS;//一个处理，一个等待，
                    keys[pair].step=KEY_STEP_DOUBLE_WAIT;
                    time_double = (keys[i].step_time < keys[pair].step_time) ? keys[i].step_time: keys[pair].step_time;
                    keys[i].step_time = time_double;//统一时间，取最小的那个
                    keys[pair].step_time = time_double;//统一时间，取最小的那个

                }
            break;
            case KEY_STEP_DOUBLE_WAIT:
            break;
            case KEY_STEP_DOUBLE_PROCESS:
                pair=key_bsp_keys_get(keys[i].pair);
                if(keys[i].step_time < keys[pair].step_time)
                    time_double = keys[pair].step_time - keys[i].step_time;
                else
                    time_double = keys[i].step_time - keys[pair].step_time;

                double_key = (1<<index) | (1<<pair);
                if((KEY_STATE_ENABLE == keys[i].state) && (KEY_STATE_ENABLE == keys[pair].state))
                {
                    if((0!=KEY_PRESS_LONG_HOLD_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_HOLD_TIME))
                    {
                        if(keys[i].step_time==KEY_PRESS_LONG_HOLD_TIME)
                            key_bsp.function(double_key,KEY_PRESS_LONG_HOLD);
                        else
                        {//长按循环执行
                            if((0!=KEY_PRESS_HOLD_INTERVAL_TIME) && (0 == (keys[i].step_time%KEY_PRESS_HOLD_INTERVAL_TIME)))
                                key_bsp.function(double_key,KEY_PRESS_LONG_HOLD);
                        }
                    }
                    else if((0!=KEY_PRESS_LONG_TIME) && (keys[i].step_time==KEY_PRESS_LONG_TIME))
                        key_bsp.function(double_key,KEY_PRESS_LONG_START);
                    else if((0!=KEY_PRESS_SHORT_TIME) && (keys[i].step_time==KEY_PRESS_SHORT_TIME))
                        key_bsp.function(double_key,KEY_PRESS_SHORT_START);
                }
                else if((time_double<=KEY_PRESS_DOUBLE_END_YIME) && \
                        (KEY_STATE_DISABLE == keys[i].state) && \
                        (KEY_STATE_ENABLE == keys[pair].state))
                {
                    keys[i].step_time -= KEY_SCAN_TIME;//暂停
                }
                else if((time_double<=KEY_PRESS_DOUBLE_END_YIME) && \
                        (KEY_STATE_ENABLE == keys[i].state) && \
                        (KEY_STATE_DISABLE == keys[pair].state))
                {
                    keys[pair].step_time -= KEY_SCAN_TIME;//暂停
                }
                else
                {
                    if((0!=KEY_PRESS_LONG_HOLD_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_HOLD_TIME))
                        key_bsp.function(double_key,KEY_PRESS_LONG_HOLD_UP);
                    else if((0!=KEY_PRESS_LONG_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_TIME))
                        key_bsp.function(double_key,KEY_PRESS_LONG_UP);
                    else if((0!=KEY_PRESS_SHORT_TIME) && (keys[i].step_time>=KEY_PRESS_SHORT_TIME))
                        key_bsp.function(double_key,KEY_PRESS_SHORT_UP);
                    else
                        key_bsp.function(double_key,KEY_PRESS_SINGLE_CLICK);

                    keys[i].step = KEY_STEP_IDLE;
                    keys[pair].step = KEY_STEP_IDLE;
                    keys[i].step_time=0;
                    keys[pair].step_time=0;
                }
            break;

            case KEY_STEP_SINGLE_PROCESS:
                if(KEY_STATE_ENABLE == keys[i].state)
                {
                    if(keys[i].click_cnt>0)
                    {
                        if(keys[i].step_time>KEY_MULTIPLE_INTERVAL)
                        {
                            E_KEY_TYPE press_type = (1==keys[i].click_cnt) ? KEY_PRESS_SINGLE_CLICK: \
                                                   ((2==keys[i].click_cnt) ? KEY_PRESS_DOUBLE_CLICK: KEY_PRESS_REPEAT_CLICK);
                            keys[i].click_cnt=0;
                            keys[i].step_time=0;
                            key_bsp.function(1<<index, press_type);
                        }

                    }
                    else if((0!=KEY_PRESS_LONG_HOLD_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_HOLD_TIME))
                    {
                        if(keys[i].step_time==KEY_PRESS_LONG_HOLD_TIME)
                            key_bsp.function(1<<index, KEY_PRESS_LONG_HOLD);
                        else
                        {
                            if((0!=KEY_PRESS_HOLD_INTERVAL_TIME) && (0 == (keys[i].step_time%KEY_PRESS_HOLD_INTERVAL_TIME)))
                                key_bsp.function(1<<index, KEY_PRESS_LONG_HOLD);
                        }
                    }
                    else if((0!=KEY_PRESS_LONG_TIME) && (keys[i].step_time==KEY_PRESS_LONG_TIME))
                        key_bsp.function(1<<index, KEY_PRESS_LONG_START);
                    else if((0!=KEY_PRESS_SHORT_TIME) && (keys[i].step_time==KEY_PRESS_SHORT_TIME))
                        key_bsp.function(1<<index, KEY_PRESS_SHORT_START);
                }
                else
                {
                    if((0!=KEY_PRESS_LONG_HOLD_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_HOLD_TIME))
                        key_bsp.function(1<<index, KEY_PRESS_LONG_HOLD_UP);
                    else if((0!=KEY_PRESS_LONG_TIME) && (keys[i].step_time>=KEY_PRESS_LONG_TIME))
                        key_bsp.function(1<<index, KEY_PRESS_LONG_UP);
                    else if((0!=KEY_PRESS_SHORT_TIME) && (keys[i].step_time>=KEY_PRESS_SHORT_TIME))
                        key_bsp.function(1<<index, KEY_PRESS_SHORT_UP);
                    else
                    {
                        keys[i].step=KEY_STEP_MULTIPLE_CLICK;
                        keys[i].click_cnt++;
                        keys[i].step_time=0;
                    }
                    if(KEY_STEP_MULTIPLE_CLICK!=keys[i].step)
                        keys[i].step=KEY_STEP_IDLE;
                }

            break;
            case KEY_STEP_MULTIPLE_CLICK:
                if(KEY_STATE_ENABLE == keys[i].state)
                {
                    if(keys[i].step_time>=KEY_DEBOUNCE_TIME)  {
                        keys[i].step=KEY_STEP_SINGLE_PROCESS;
                        keys[i].step_time=0;
                    }
                }
                else if(keys[i].step_time>KEY_MULTIPLE_INTERVAL)
                {
                    E_KEY_TYPE press_type = (1==keys[i].click_cnt) ? KEY_PRESS_SINGLE_CLICK: \
                                          ((2==keys[i].click_cnt) ? KEY_PRESS_DOUBLE_CLICK: KEY_PRESS_REPEAT_CLICK);
                    keys[i].step=KEY_STEP_IDLE;
                    key_bsp.function(1<<index, press_type);
                }
            break;

            default:break;
        }
    }
}
static void key_bsp_param_default()
{
    for(int i=0; i<KEY_MAX; i++)
    {
        keys[i].index = (E_KEY)i;//可以从存储flash中读取，作为记忆按键
        keys[i].step = KEY_STEP_IDLE;
        keys[i].step_time  = 0;
        keys[i].state = KEY_STATE_DISABLE;
        keys[i].pair = KEY_MAX;//可以从存储flash中读取，作为记忆按键
    }
}

static void key_bsp_double_Key_set(u32 val)
{
    for(int i=0; i<KEY_MAX; i++)
    {
        for(int j=i+1; j<KEY_MAX; j++) {
            if((val & (1<<i)) && (val & (1<<j)))
            {
                keys[i].pair = (E_KEY)j;
                keys[j].pair = (E_KEY)i;
                return ;
            }
        }
    }
}
void key_bsp_callback_set(key_bsp_callback func)
{
    key_bsp.function = func;
}
void key_bsp_init(void)
{
    key_bsp_param_default();//在io初始化之前执行

     for(int i=0; i<KEY_MAX; i++)
        key_driver_gpio_init((E_KEY)i);

    key_bsp_double_Key_set(KEY_TEST4);//双按键设置
    work_add_tail(key_bsp_scan,0);
}

void key_bsp_uninit(void)
{
    work_del(key_bsp_scan,0);
    for(int i=0; i<KEY_MAX; i++)
        key_driver_gpio_uninit((E_KEY)i);
}
void key_bsp_function_change(E_KEY val0,E_KEY val1)
{
    if((val0>=KEY_MAX) || (val0>=KEY_MAX) || (val0 == val1))
        return ;

    E_KEY key = keys[val0].index;
    keys[val0].index = keys[val1].index;
    keys[val1].index = key;

    key = keys[val0].pair;
    keys[val0].pair = keys[val1].pair;
    keys[val1].pair = key ;

    //flash 保存，
}

